package com.ziytek.web.citizen.service.impl;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.ziytek.web.citizen.caffeine.PositionCacheConfig;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import com.ziytek.web.citizen.enums.StepNameEnum;
import com.ziytek.web.citizen.event.BatteryExportNotifyEvent;
import com.ziytek.web.citizen.export.ExportDataExcel;
import com.ziytek.web.citizen.export.excl.ChartPosition;
import com.ziytek.web.citizen.export.excl.ChartUtils;
import com.ziytek.web.citizen.export.excl.LineChartModel;
import com.ziytek.web.citizen.mapper.BasicStepSettingsMapper;
import com.ziytek.web.citizen.model.bean.AddSettings;
import com.ziytek.web.citizen.model.bean.DbNameList;
import com.ziytek.web.citizen.model.bean.StageDataMap;
import com.ziytek.web.citizen.model.req.BatteryComprehensiveExportReq;
import com.ziytek.web.citizen.model.req.BatteryExportReq;
import com.ziytek.web.citizen.model.req.BatteryListQueryReq;
import com.ziytek.web.citizen.model.rsp.QueryDbNameRsp;
import com.ziytek.web.citizen.model.rsp.QueryFileNameRsp;
import com.ziytek.web.citizen.model.rsp.UnifyResponse;
import com.ziytek.web.citizen.pojo.basic.BasicStepSettings;
import com.ziytek.web.citizen.service.itf.BatteryExportService;
import com.ziytek.web.citizen.service.itf.ExportFileNameService;
import com.ziytek.web.citizen.service.itf.HistoryDbQueryService;
import com.ziytek.web.citizen.util.*;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * @className BatteryExportServiceImpl
 * @description: 描述
 * @jdkVersion: 1.8
 * @author: fhx
 * @date: 2024/7/2 9:53
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class BatteryExportServiceImpl implements BatteryExportService {

    private final Gson gson;
    private final ApplicationContext context;
    private final PositionCacheConfig positionCacheConfig;
    private final HistoryDbQueryService historyDbQueryService;
    private final ExportFileNameService exportFileNameService;
    private final BasicStepSettingsMapper basicStepSettingsMapper;

    private static final int QUERY_LIMIT = 8192;

    private static final int ZIP_COUNT = NumConstant.INT_THREE;
    private static final Map<String, Integer> MAP_ZIP_COUNT_FAIL = new ConcurrentHashMap<>();

    private void httpResponseError(HttpServletResponse httpResponse, String msg) {
        try {
            UnifyResponse unifyResponse = new UnifyResponse();
            unifyResponse.error(msg);
            log.error("实时曲线数据导出失败:{}", msg);
            OutputStream out = httpResponse.getOutputStream();
            out.write(gson.toJson(unifyResponse).getBytes(StandardCharsets.UTF_8));
            out.close();
        } catch (Exception e) {
            log.error("导出数据失败:", e);
        }
    }

    @Override
    public void batteryExportZip(BatteryExportReq request, HttpServletResponse httpResponse) {
        if (request == null || StringUtil.isEmpty(request.getCabinetNo()) || StringUtil.isEmpty(request.getExportFileName())) {
            httpResponseError(httpResponse, "接口请求参数检验失败");
            return;
        }

        Date exportNameDate = request.getExportNameDate();
        String name = request.getExportFileName();
        if (exportNameDate == null) {
            httpResponseError(httpResponse, "接口请求参数检验失败");
            return;
        }

        String outFileNames = "";
        QueryFileNameRsp fileNameRsp = exportFileNameService.queryFileNameByCabinetId(CabinetNoUtil.getCabinetNo(request.getCabinetNo()));
        if (fileNameRsp != null && !CollectionUtils.isEmpty(fileNameRsp.getData())) {
            fileNameRsp.getData().sort(Comparator.reverseOrder());
            for (String k : fileNameRsp.getData()) {
                Date dateFile = null;
                try {
                    dateFile = DateUtils.parseDate(k.replace(".zip", "")
                            .replace("_", "")
                            .replace(".ZIP", ""), ServerConstant.DATE_FORMAT_TWO);
                } catch (Exception e) {
                    log.info("日期格式错误,请检查日期格式是否正确,格式:{}", k, e);
                }
                // 相差20秒内
                if (dateFile != null && Math.abs(dateFile.getTime() - exportNameDate.getTime()) <= (NumConstant.INT_ONE_THOUSAND * NumConstant.INT_TWO_TEN)) {
                    outFileNames = k;
                    break;
                }
            }
        }

        if (StringUtil.isEmpty(outFileNames)) {
            httpResponseError(httpResponse, name + "文件不存在");
            return;
        }

        String cabinetNo = CabinetNoUtil.getCabinetNo(request.getCabinetNo());
        // 设置下载文件名

        String locationAddress = LocationUtils.getLocation();
        log.info("当前项目数据库文件路径：{}", locationAddress);
        // 文件不存在
        File folder = new File(locationAddress + "/download/" + cabinetNo + "/" + outFileNames);
        if (!folder.exists()) {
            log.info("文件夹[{}]不存在", locationAddress + "/download/" + cabinetNo + "/" + outFileNames);
            httpResponseError(httpResponse, "导出zip压缩包失败,文件不存在");
            return;
        }

        try {
            httpResponse.reset();
            httpResponse.setHeader("Content-disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(outFileNames, StandardCharsets.UTF_8));
            httpResponse.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            httpResponse.setCharacterEncoding("UTF-8");
            httpResponse.setContentType("application/zip; charset=utf-8");

            // 初始化输出流到response
            InputStream in = Files.newInputStream(Paths.get(locationAddress + "/download/" + cabinetNo + "/" + outFileNames));
            OutputStream toClient = getOutputStream(httpResponse, in);
            toClient.close();
            in.close();
            //httpResponseSuccess(httpResponse);
        } catch (IOException e) {
            // 处理异常
            log.error("导出zip压缩包失败:", e);
            httpResponseError(httpResponse, "导出zip压缩包失败");
        }
    }

    private static OutputStream getOutputStream(HttpServletResponse httpResponse, InputStream in) throws IOException {
        ZipInputStream zin = new ZipInputStream(in);
        OutputStream toClient = new BufferedOutputStream(httpResponse.getOutputStream());
        ZipOutputStream zipOutputStream = new ZipOutputStream(toClient);

        ZipEntry entry;
        while ((entry = zin.getNextEntry()) != null) {
            // 不解压就直接写入到目标ZIP文件
            zipOutputStream.putNextEntry(entry);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = zin.read(buffer)) > 0) {
                zipOutputStream.write(buffer, 0, length);
            }
            zin.closeEntry();
        }
        zipOutputStream.finish();
        toClient.flush();
        return toClient;
    }

    @Override
    public void batteryExportNotify(String cabinetNo, String fileName) {
        if (StringUtil.isEmpty(cabinetNo) || StringUtil.isEmpty(fileName)) {
            log.info("batteryExportNotify cabinetNo is empty or fileName is empty.");
            throw new RuntimeException("batteryExportNotify cabinetNo is empty or fileName is empty.");
        }
        log.info("Start generating real-time curve report data ZIP compressed file，cabinetNo:{}", cabinetNo);

        cabinetNo = CabinetNoUtil.getCabinetNo(cabinetNo);
//        if (GlobalConfig.isStepSwitching()) {
//            log.info("Batch Export database change in progress");
//            throw new RuntimeException("Batch Export database change in progress");
//        }

//        IssuedHistorySetting issuedHistorySetting = issuedHistorySettingMapper.findFirstByCabinetNoOrderByCreateTimeDesc(cabinetNo);
//        if (issuedHistorySetting == null) {
//            throw new RuntimeException("No data found");
//        }

        // Long stepId = issuedHistorySetting.getStepId();
        Long stepId = 0L;
        BasicStepSettings basicStepSettings = basicStepSettingsMapper.findFirstById(stepId);
        if (basicStepSettings == null) {
            throw new RuntimeException("No data found");
        }

        int chargeCurrentLimit = basicStepSettings.getChargeCurrentLimit();

        List<AddSettings> settings = gson.fromJson(basicStepSettings.getStepSettings(), new TypeToken<List<AddSettings>>() {
        }.getType());
        if (CollectionUtils.isEmpty(settings)) {
            throw new RuntimeException("No data found");
        } else {
            settings.sort(Comparator.comparing(AddSettings::getSettingOrder));
        }

        //long createTime = issuedHistorySetting.getCreateTime();
        long createTime = 0L;
        long startTimeSecond = createTime / NumConstant.INT_ONE_THOUSAND;
        long startTime = startTimeSecond * NumConstant.INT_ONE_THOUSAND;

        // startTime = 1724392034000L;// 测试数据

        long queryStartTime = System.currentTimeMillis();
        List<StageDataMap> stageDataMapList = new ArrayList<>();
        List<StageDataMap> queryList = null;
        int startLimit = NumConstant.INT_ZERO;
        do {
            //queryList = stageBatchMapper.queryListByCabinetNoAndLimit(cabinetNo, startTime, startLimit, QUERY_LIMIT);
            startLimit += QUERY_LIMIT;
            stageDataMapList.addAll(queryList);
        } while (!CollectionUtils.isEmpty(queryList) && queryList.size() == QUERY_LIMIT);

        log.info("Generation of real-time curve report ZIP compressed package data query time: {}ms, Total amount of query data: {}", System.currentTimeMillis() - queryStartTime, stageDataMapList.size());
        queryList.clear();

        long mapStartTime = System.currentTimeMillis();
        if (CollectionUtils.isEmpty(stageDataMapList)) {
            throw new RuntimeException("No data found");
        }

        Map<String, List<StageDataMap>> map = stageDataMapList.stream().collect(Collectors.groupingBy(StageDataMap::getKey));
        log.info("Generating real-time curve report ZIP compressed package data to map time: {} ms, total number of maps: {}", System.currentTimeMillis() - mapStartTime, map.size());

        stageDataMapList.clear();

        long start = System.currentTimeMillis();

        exportLocalZip(basicStepSettings, map, cabinetNo, createTime, settings, chargeCurrentLimit);

        log.info("Generating real-time curve report ZIP compressed file locally takes time:{}ms", System.currentTimeMillis() - start);
    }


    @Override
    public UnifyResponse batteryExportNotifyByCabinetIds(String cabinetIds) {
        UnifyResponse response = new UnifyResponse();
        response.error("Real time curve report data generation ZIP failed");
        if (StringUtil.isEmpty(cabinetIds)) {
            log.error("batteryExportNotifyByCabinetIds cabinetIds is empty.");
            response.error("cabinetIds is empty");
            return response;
        }

        String fileName = "";
        QueryDbNameRsp dbNameRsp = historyDbQueryService.queryAllDbName();
        if (dbNameRsp == null || CollectionUtils.isEmpty(dbNameRsp.getData())) {
            log.error("batteryExportNotifyByCabinetIds No database found ids:{}", cabinetIds);
            response.error("No database found");
            return response;
        }

        List<DbNameList> dbNameLists = dbNameRsp.getData();
        dbNameLists.sort((o1, o2) -> o2.getDateString().compareTo(o1.getDateString()));
        DbNameList dbNameList = dbNameLists.getFirst();
        if (dbNameList == null || CollectionUtils.isEmpty(dbNameList.getTimeFormat())) {
            log.error("batteryExportNotifyByCabinetIds DbNameList is empty. dbNameLists:{}", dbNameLists);
            response.error("DbNameList is empty");
            return response;
        }

        String dateString = dbNameList.getDateString();
        List<String> dbNames = dbNameList.getTimeFormat();
        dbNames.sort(Comparator.reverseOrder());
        String dbName = dbNames.getFirst().replace(ServerConstant.STR_EMPTY_TWO, ServerConstant.STR_EMPTY);
        fileName = dateString + dbName;

        log.info("Start generating real-time curve report data ZIP compressed file，cabinetId:{}", cabinetIds);
        String cabinetNo = CabinetNoUtil.getCabinetNo(cabinetIds);
        context.publishEvent(new BatteryExportNotifyEvent(cabinetNo, fileName));

        response.success();
        return response;
    }


    private void check(BatteryComprehensiveExportReq request) {
        if (request == null) {
            throw new RuntimeException("batteryComprehensiveExport failed request is empty.");
        }

        if (!request.requestCheck()) {
            throw new RuntimeException("Interface request parameter verification failed");
        }
//
//        if (GlobalConfig.isStepSwitching()) {
//            log.info("BatteryDetailsQuery database change in progress, accepting data without processing");
//            throw new RuntimeException("BatteryDetailsQuery database change in progress, accepting data without processing");
//        }

    }

    @Override
    public void batteryComprehensiveExport(BatteryComprehensiveExportReq request, HttpServletResponse httpResponse) {
        check(request);

        BatteryListQueryReq req = new BatteryListQueryReq();
        req.setCabinetNo(request.getCabinetNo());

//        LinkedHashMap<String, List<StageComprehensiveTable>> map = batteryComprehensiveService.getStageDataMapList(req);
//        if (CollectionUtils.isEmpty(map)) {
//            throw new RuntimeException("No data found");
//        }

        request.requestCheckFileName();
        String fileName = request.getExportFileName();
        // comprehensiveExport(map, fileName, httpResponse);
    }

    private void exportLocalZip(BasicStepSettings basicStepSetting, Map<String, List<StageDataMap>> map, String cabinetNo, long startTime, List<AddSettings> settings, int chargeCurrentLimit) {
        if (CollectionUtils.isEmpty(map)) {
            log.info("exportLocalZip No data found, map is empty.");
            throw new RuntimeException("No data found");
        }

        try {
            exportDataExcelProcessList(basicStepSetting, cabinetNo, map, settings, chargeCurrentLimit, startTime);
        } catch (Exception e) {
            log.error("exportLocalZip exportDataExcelProcessList error failed:", e);
            throw new RuntimeException(e);
        }
    }

//    private void comprehensiveExport(LinkedHashMap<String, List<StageComprehensiveTable>> map, String fileName, HttpServletResponse httpResponse) {
//        if (CollectionUtils.isEmpty(map)) {
//            throw new RuntimeException("No data found");
//        }
//
//
//        httpResponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//        //httpResponse.setHeader("Content-Disposition", "attachment;filename=output.xlsx");
//        httpResponse.setHeader("Content-Disposition", "attachment;filename=" + fileName + "_export.xlsx");
//
//        List<ComprehensiveExportDataExcel> excels = getComprehensiveExportDataExcelList(map);
//
//        try {
//            //List<User> users = userService.listAll(); // 假设从数据库获取数据
//            FastExcel.write(httpResponse.getOutputStream(), ComprehensiveExportDataExcel.class)
//                    .sheet("电池综合数据")
//                    .doWrite(excels);
//        } catch (Exception e) {
//            log.error("comprehensiveExport error:", e);
//            throw new RuntimeException(e);
//        }
////        // 导出实现
////        try (Workbook sheets = ExcelExportUtil.exportExcel(new ExportParams(null, "电池综合数据"), ComprehensiveExportDataExcel.class, excels)) {
////            httpResponse.reset();
////            httpResponse.setContentType("application/vnd.ms-excel;charset=UTF-8");
////            httpResponse.setHeader("Content-disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(fileName + "_export.xlsx", StandardCharsets.UTF_8));
////            httpResponse.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
////            httpResponse.setCharacterEncoding("UTF-8");
////            sheets.write(httpResponse.getOutputStream());
////        } catch (Exception e) {
////            throw new RuntimeException(e);
////        }
//    }

    private void exportDataExcelProcessList(BasicStepSettings basicStepSetting, String cabinetNo, Map<String, List<StageDataMap>> map, List<AddSettings> settings, int chargeCurrentLimit, long startTime) {

        String beginTimeStr = DateFormatUtils.format(startTime, ServerConstant.DATE_FORMAT);
        LocationUtils.downloadLocation(cabinetNo, beginTimeStr);

        CompletableFuture<List<Integer>> completableFuture = xssWorkProcess(basicStepSetting, map, settings, chargeCurrentLimit, beginTimeStr);
        List<Integer> integerList = completableFuture.join();

        String location = LocationUtils.downloadLocationPath(cabinetNo, beginTimeStr);
        ZipUtil.zipDirectoryAsync(location, location + ".zip");
        boolean isSuccess = ZipUtil.zipFileExistsAndSizeNotEmpty(location + ".zip", 1024L);
        log.info("Real time curve data export ZIP compressed file generation result:{},integerListSize:{}", isSuccess, integerList.size());
        //isSuccess = false; // 测试
        String cacheKey = cabinetNo + startTime;
        int count = MAP_ZIP_COUNT_FAIL.getOrDefault(cacheKey, NumConstant.INT_ZERO);
        if (isSuccess) {
            boolean deleteSuccess = ZipUtil.deleteDirectorySync(location);
            log.info("Real time curve data export ZIP compressed file temporary file deletion result:{}", deleteSuccess);
            MAP_ZIP_COUNT_FAIL.remove(cacheKey);

            String key = CabinetNoUtil.getCabinetNo(cabinetNo) + (beginTimeStr.length() >= NumConstant.INT_TEN ? beginTimeStr.substring(NumConstant.INT_ZERO, NumConstant.INT_TEN) : "");
            //GlobalConfig.setExportDataIng(key, false);
        } else {
            if (count <= ZIP_COUNT) {
                try {
                    Thread.sleep(count * NumConstant.LONG_TWO * NumConstant.LONG_ONE_THOUSAND);
                } catch (Exception e) {
                    log.error("sleep error:", e);
                }
                // 重新打包ZIP压缩包
                log.info("Real time curve data export ZIP compression file generation failed, regenerate ZIP compression file,count:{}", count);
                MAP_ZIP_COUNT_FAIL.put(cacheKey, count + NumConstant.INT_ONE);

                exportDataExcelProcessList(basicStepSetting, cabinetNo, map, settings, chargeCurrentLimit, startTime);
            } else {
                MAP_ZIP_COUNT_FAIL.remove(cacheKey);
                log.error("Real time curve data export ZIP compressed file generation failed, exceeding the maximum retry count:{}", ZIP_COUNT);
            }
        }
    }

    public CompletableFuture<List<Integer>> xssWorkProcess(BasicStepSettings basicStepSetting, Map<String, List<StageDataMap>> map, List<AddSettings> settings, int chargeCurrentLimit, String beginTimeStr) {
        if (CollectionUtils.isEmpty(map)) {
            return CompletableFuture.completedFuture(Collections.singletonList(NumConstant.INT_ZERO));
        }

        // 使用CompletableFuture的allOf方法等待所有查询完成
        List<CompletableFuture<List<Integer>>> futures = new ArrayList<>();

        for (Map.Entry<String, List<StageDataMap>> entry : map.entrySet()) {
            CompletableFuture<List<Integer>> future = CompletableFuture.supplyAsync(()
                    -> xssWorkOneAsync(basicStepSetting, entry.getKey(), entry.getValue(), settings, chargeCurrentLimit, beginTimeStr), VirtualThreadUtil.getExecutor());
            futures.add(future);
        }

        // 使用CompletableFuture的allOf方法等待所有查询完成
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[NumConstant.INT_ZERO]));

        // 当所有查询完成时，对所有结果进行合并
        CompletableFuture<List<Integer>> mergedResult = allFutures.thenApply(v ->
                futures.stream().map(CompletableFuture::join).flatMap(List::stream)
                        .collect(Collectors.toList()));

        // 阻塞等待合并结果
        List<Integer> detailsList = mergedResult.join();
        if (CollectionUtils.isEmpty(detailsList)) {
            return CompletableFuture.completedFuture(Collections.singletonList(NumConstant.INT_ZERO));
        }

        return CompletableFuture.completedFuture(detailsList);
    }

    public List<Integer> xssWorkOneAsync(BasicStepSettings basicStepSetting, String key, List<StageDataMap> stageDataMapList, List<AddSettings> settings, int maxChargeLimitCurrent, String beginTimeStr) {
        // 导出实现
        LineChartModel lineChartModel = getLineChartModelListFromStageDataMap(stageDataMapList);
        List<ExportDataExcel> exportDataExcels = getExportDataExcelListSync(stageDataMapList);

        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet("电池曲线实时数据");

        AtomicInteger sheetNum = new AtomicInteger(sheet.getPhysicalNumberOfRows());
        Row heardeRow = sheet.createRow(sheet.getPhysicalNumberOfRows());
        heardeRow.createCell(NumConstant.INT_ZERO).setCellValue("序列号");
        heardeRow.createCell(NumConstant.INT_ONE).setCellValue("类型");
        heardeRow.createCell(NumConstant.INT_TWO).setCellValue("电芯编号");
        heardeRow.createCell(NumConstant.INT_THREE).setCellValue("电压");
        heardeRow.createCell(NumConstant.INT_FOUR).setCellValue("电流");
        heardeRow.createCell(NumConstant.INT_FIVE).setCellValue("容量");
        heardeRow.createCell(NumConstant.INT_SIX).setCellValue("执行时间");
        heardeRow.createCell(NumConstant.INT_SEVEN).setCellValue("累计时间(分钟)");

        Thread thread = Thread.ofVirtual().start(() -> {
            for (ExportDataExcel el : exportDataExcels) {
                sheetNum.getAndIncrement();
                // 创建单元格并设置值
                Row row = sheet.createRow(sheetNum.get());
                row.createCell(NumConstant.INT_ZERO).setCellValue(el.getSeq());
                row.createCell(NumConstant.INT_ONE).setCellValue(el.getType());
                row.createCell(NumConstant.INT_TWO).setCellValue(el.getBatteryNum());
                row.createCell(NumConstant.INT_THREE).setCellValue(el.getVoltage());
                row.createCell(NumConstant.INT_FOUR).setCellValue(el.getCurrent());
                row.createCell(NumConstant.INT_FIVE).setCellValue(el.getCapacity());
                row.createCell(NumConstant.INT_SIX).setCellValue(el.getExecuteTime());
                row.createCell(NumConstant.INT_SEVEN).setCellValue(el.getTotalTime());
            }
        });

        try {
            thread.join();
        } catch (InterruptedException e) {
            log.error("thread join error:", e);
        }
        //清除数据
        exportDataExcels.clear();
        //-------------------------折线图--------------------------
        if (lineChartModel != null) {
            XSSFSheet xssfSheetLine = workbook.createSheet("曲线图");
            // 图表位置（左上角坐标，右下角坐标） 左上角坐标的（列，行），（右下角坐标）列，行,偏移量均为0
            ChartPosition chartPosition = new ChartPosition()
                    .setRow1(0)
                    .setCol1(0)
                    .setRow2(30)
                    .setCol2(18);
            ChartUtils.createLineDouble(xssfSheetLine, chartPosition, lineChartModel);
        }
        if (!CollectionUtils.isEmpty(settings)) {
            XSSFSheet xssfSheetSettings = workbook.createSheet("工步设置");
            ChartUtils.createTableMsg(basicStepSetting, 0, workbook, xssfSheetSettings, settings, maxChargeLimitCurrent);
        }

        ZipUtil.xlsxCreateAndSave(workbook, key, beginTimeStr);
        return Collections.singletonList(NumConstant.INT_ONE);
    }

    private List<ExportDataExcel> getExportDataExcelListSync(List<StageDataMap> stageDataMapList) {
        List<ExportDataExcel> excels = new ArrayList<>();

        List<ExportDataExcel> finalExcels = excels;
        long start = System.currentTimeMillis();
        // 虚拟线程处理
        Thread thread = Thread.ofVirtual().start(() -> {
            for (StageDataMap stage : stageDataMapList) {
                ExportDataExcel exportDataExcel = new ExportDataExcel();
                String[] keyArr = stage.getKey().split(ServerConstant.DATA_SEPARATOR);
                if (keyArr.length != NumConstant.INT_THREE) {
                    continue;
                }

                String queryKey = keyArr[NumConstant.INT_ONE] + ServerConstant.DATA_SEPARATOR + keyArr[NumConstant.INT_TWO];
                exportDataExcel.setBatteryNum(positionCacheConfig.getPositionSeqValue(queryKey));
                exportDataExcel.setSeq(positionCacheConfig.getPositionSeq(queryKey));

                exportDataExcel.setType(StepNameEnum.STEP_CC.getMsg(stage.getSetType()));
                exportDataExcel.setCapacity(String.valueOf(stage.getCap()));
                // 分钟
                long minute = stage.getAt() / NumConstant.LONG_SIXTY;
                // 秒
                long second = stage.getAt() % NumConstant.LONG_SIXTY;
                exportDataExcel.setTotalTime(minute + "分" + second + "秒");
                exportDataExcel.setExecuteTime(DateFormatUtils.format(stage.getCt(), ServerConstant.DATE_FORMAT));
                exportDataExcel.setCurrent(String.valueOf(stage.getC()));
                exportDataExcel.setVoltage(String.valueOf(stage.getV()));
                finalExcels.add(exportDataExcel);
            }
        });

        try {
            long end = System.currentTimeMillis();
            thread.join();
            //log.info("getExportDataExcelListSync time:{}ms", end - start);
        } catch (InterruptedException e) {
            log.error("thread join error:", e);
        }

//        for (StageDataMap stage : stageDataMapList) {
//            ExportDataExcel exportDataExcel = new ExportDataExcel();
//            String[] keyArr = stage.getKey().split(ServerConstant.DATA_SEPARATOR);
//            if (keyArr.length != NumConstant.INT_THREE) {
//                continue;
//            }
//
//            String queryKey = keyArr[NumConstant.INT_ONE] + ServerConstant.DATA_SEPARATOR + keyArr[NumConstant.INT_TWO];
//            exportDataExcel.setBatteryNum(positionCacheConfig.getPositionSeqValue(queryKey));
//            exportDataExcel.setSeq(positionCacheConfig.getPositionSeq(queryKey));
//
//            exportDataExcel.setType(StepNameEnum.STEP_CC.getMsg(stage.getSetType()));
//            exportDataExcel.setCapacity(String.valueOf(stage.getCap()));
//            // 分钟
//            long minute = stage.getAt() / NumConstant.LONG_SIXTY;
//            // 秒
//            long second = stage.getAt() % NumConstant.LONG_SIXTY;
//            exportDataExcel.setTotalTime(minute + "分" + second + "秒");
//            exportDataExcel.setExecuteTime(DateFormatUtils.format(stage.getCt(), ServerConstant.DATE_FORMAT));
//            exportDataExcel.setCurrent(String.valueOf(stage.getC()));
//            exportDataExcel.setVoltage(String.valueOf(stage.getV()));
//            excels.add(exportDataExcel);
//        }

        excels = finalExcels.stream().sorted(Comparator.comparingInt(ExportDataExcel::getSeq)).collect(Collectors.toList());
        int seq = NumConstant.INT_ONE;
        List<ExportDataExcel> result = new ArrayList<>();
        for (ExportDataExcel e : excels) {
            e.setSeq(seq);
            result.add(e);
            seq++;
        }
        // 清除数据
        return result;
    }

//    private List<ComprehensiveExportDataExcel> getComprehensiveExportDataExcelList(LinkedHashMap<String, List<StageComprehensiveTable>> map) {
//        Map<String, List<ComprehensiveExportDataExcel>> excelMap = new LinkedHashMap<>();
//        for (Map.Entry<String, List<StageComprehensiveTable>> entry : map.entrySet()) {
//            String type = entry.getKey();
//            List<ComprehensiveExportDataExcel> excels = new ArrayList<>();
//            List<StageComprehensiveTable> stageDataMapList = entry.getValue();
//            for (StageComprehensiveTable stage : stageDataMapList) {
//                ComprehensiveExportDataExcel c = new ComprehensiveExportDataExcel();
//                c.setType(type);
//                c.setExecuteTime(stage.getExecutedTime());
//                c.setCurrent(String.valueOf(stage.getCurrent()));
//                c.setVoltage(String.valueOf(stage.getVoltage()));
//                c.setCapacity(String.valueOf(stage.getCapacity()));
//
//                String[] keyArr = stage.getKey().split(ServerConstant.DATA_SEPARATOR);
//                if (keyArr.length != NumConstant.INT_THREE) {
//                    continue;
//                }
//                String tier = keyArr[NumConstant.INT_ONE];
//                tier = NumberUtils.toInt(tier) > NumConstant.INT_EIGHT ? String.valueOf(NumberUtils.toInt(tier) - NumConstant.INT_EIGHT) : tier;
//
//                String queryKey = keyArr[NumConstant.INT_ONE] + ServerConstant.DATA_SEPARATOR + keyArr[NumConstant.INT_TWO];
//                c.setBatteryNum(positionCacheConfig.getPositionSeqValue(queryKey));
//                c.setSeq(positionCacheConfig.getPositionSeq(queryKey));
//
//                c.setCabinetNo(keyArr[NumConstant.INT_ZER]);
//                c.setTileNum(tier);
//
//                String ps = keyArr[NumConstant.INT_TWO];
//                ps = NumberUtils.toInt(ps) > NumConstant.INT_TEN_SIX ? String.valueOf(NumberUtils.toInt(ps) - NumConstant.INT_TEN_SIX) : ps;
//                c.setPosition(ps);
//
//                excels.add(c);
//            }
//            excels.sort(Comparator.comparingInt(ComprehensiveExportDataExcel::getSeq));
//            excelMap.put(type, excels);
//        }
//
//        List<ComprehensiveExportDataExcel> result = excelMap.values().stream().flatMap(List::stream).toList();
//        if (CollectionUtils.isEmpty(result)) {
//            throw new RuntimeException("No data found");
//        }
//
//        List<ComprehensiveExportDataExcel> newResult = new ArrayList<>();
//        int seq = NumConstant.INT_ONE;
//        for (ComprehensiveExportDataExcel c : result) {
//            c.setSeq(seq);
//            newResult.add(c);
//            seq++;
//        }
//
//        return newResult;
//    }

    private LineChartModel getLineChartModelListFromStageDataMap(List<StageDataMap> stageDataMapList) {
        if (CollectionUtils.isEmpty(stageDataMapList)) {
            log.error("line graph:{}", "No data found");
            return null;
        }

        List<StageDataMap> newLlist = stageDataMapList.stream().filter(t -> StringUtil.isNotEmpty(t.getSt())).toList();
        if (CollectionUtils.isEmpty(newLlist)) {
            log.error("line graph StageDataMap:{}", "No data found");
            return null;
        }

        List<StageDataMap> list = newLlist.stream().sorted(Comparator.comparing(StageDataMap::getCt)).toList();

        List<Integer> voltageList = new ArrayList<>();
        List<Integer> currentList = new ArrayList<>();
        List<Object> timeList = new ArrayList<>();
        int i = NumConstant.INT_ZERO;
        for (StageDataMap e : list) {
            voltageList.add(e.getV().intValue());
            currentList.add(e.getC().intValue());
            if (i == NumConstant.INT_ZERO) {
                timeList.add(String.valueOf(NumConstant.INT_ZERO));
                i++;
            } else {
                timeList.add(e.getSt());
            }
        }

        int size = list.size();
        int count = size / NumConstant.INT_ONE_HUNDRED;
        for (int n = NumConstant.INT_ZERO; n <= count; n++) {
            voltageList.add(null);
            currentList.add(null);
            timeList.add(null);
        }

        LineChartModel lineChartModel = new LineChartModel();
        lineChartModel.setChartTitle("实时电流电压折线图");
        lineChartModel.setTitleList(Arrays.asList("电压", "电流"));
        lineChartModel.setDataList(Arrays.asList(voltageList, currentList));
        lineChartModel.setXAxisList(timeList);
        return lineChartModel;
    }
}
